package com.mg.pluginwebservice;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mg.model.Model;
import com.mg.model.Param;
import com.mg.model.Port;
import com.mg.pluginexample2.Model2;
import com.mg.pluginexample2.ModuleBase;
import com.mg.pluginwebservice.entity.ProductData;
import com.mg.pluginwebservice.util.HttpRequestUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class MessageAssistModel extends ModuleBase {
    public MessageAssistModel(int nID) {
        super(nID);
        m_alOutputPort.add(new Port(this, Port.Type.Unknown));//输出字符串
        m_strHost = "http://172.24.176.171:8088/GWFS_GridDataShare/dataShare/getStationDataInGridWithStationType";
        m_sdfYMD = new SimpleDateFormat("yyyy-MM-dd");
        m_strVipHost = "http://183.230.183.18:8088/SPPMDataService/services/data/query";
        m_strLocHost = "http://172.24.176.171:8088/GWFS_GridDataShare/dataShare/getAltitudeWithCoordinate";
        m_strForecastValidStart = "3";
        m_strDayFormatType = "0";
    }

    public String GetGroupName() {
        return "WebHTTP";
    }

    public String GetName() {
        return "计算大户春耕春播适宜度";
    }

    public String GetDescription() {
        return "";
    }

    public boolean OnAttach(Port portFrom, Port portTo) {
        try {
            int i = FindPort(portFrom, false);
            if (i != -1)
                return true;
            i = FindPort(portTo, true);
            if (i == -1)
                return false;
            if (portFrom.GetType() != portTo.GetType())
                return false;
            ArrayList<Param> alParam = new ArrayList<Param>();
            portFrom.GetModule().GetOutputParam(portFrom, alParam);
            if (alParam.size() < 2)
                return false;

        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }

        return true;
    }

    public boolean OnDetach(Port portFrom, Port portTo) {
        if (!super.OnDetach(portFrom, portTo))
            return false;
        try {
            int i = FindPort(portTo, true);
            if (i == -1)
                return true;
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    //用于 参数->XML 等
    public int GetParam(ArrayList<Param> alParam) {
        try {
            super.GetParam(alParam);

            Model2 model = ((Model2) m_model);

            alParam.add(new Param("Host", m_strHost, "地址", "xxx.xxx.xxx.xxx:xxxx", "WebService", Param.EditType.Default));
            alParam.add(new Param("UserID", m_strUserName, "用户名", "", "WebService", Param.EditType.Default));
            alParam.add(new Param("PassWord", m_strPassword, "密码", "", "WebService", Param.EditType.Default));

            alParam.add(new Param("Origin", m_strOrigin, "场信息", "", "WebService", Param.EditType.Default));
            alParam.add(new Param("Sequence", m_strSequenceValue, "时次", "", "WebService", Param.EditType.Default));
            alParam.add(new Param("ForecastDate", m_strDate, "预报时间", "", "WebService", Param.EditType.Default));
            alParam.add(new Param("ForecastFileVersion", m_strForecastFileVersion, "文件版本", "", "WebService", Param.EditType.Default));
            alParam.add(new Param("DayFormat", m_strDayFormatType, "时间偏移（天）", "", "WebService", Param.EditType.Default));
            alParam.add(new Param("CalcDay", m_strCalcDay, "统计天数", "", "WebService", Param.EditType.Default));

        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return alParam.size();
    }

    public boolean OnParamChanged(ArrayList<Param> alParam, int nIndex, Object objValue) {
        return super.OnParamChanged(alParam, nIndex, objValue);
    }

    //用于 XML->参数 等
    public int SetParam(final ArrayList<Param> alParam) {
        int i = super.SetParam(alParam);
        try {
            m_strHost = (String) alParam.get(i++).m_objValue;
            m_strUserName = (String) alParam.get(i++).m_objValue;
            m_strPassword = (String) alParam.get(i++).m_objValue;
            m_strOrigin = (String) alParam.get(i++).m_objValue;
            m_strSequenceValue = (String) alParam.get(i++).m_objValue;
            m_strDate = (String) alParam.get(i++).m_objValue;
            m_strForecastFileVersion = (String) alParam.get(i++).m_objValue;
            m_strDayFormatType = (String) alParam.get(i++).m_objValue;
            m_strCalcDay = (String) alParam.get(i++).m_objValue;

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return i;
    }

    @SuppressWarnings("static-access")
    public boolean Execute() {

        try {
            calcRealDate();
        } catch (ParseException e) {
            return false;
        }

        m_strForecastValidEnd = String.valueOf(Integer.parseInt(m_strCalcDay) * 24 + 24);

        Map<String, ProductData> productDataMap = new HashMap<String, ProductData>();
        boolean flag = true;

        JSONObject param = new JSONObject();
        param.put("param", "{\"Function\":\"monitor.getvips\",\"CustomParams\":{areacode:\"50\"},\"Type\":2}");
        JSONArray vipJsonData = executeMethod(m_strVipHost, param, HttpRequestUtils.CONTENT_TYPE_X_FORM).getJSONArray("data");
        List<ProductData> vipData = JSON.parseArray(vipJsonData.toJSONString(), ProductData.class);
        StringBuffer coordinate = new StringBuffer();
        for (ProductData vip : vipData) {
            coordinate.append(vip.getLocaton()).append(",");
            productDataMap.put(vip.getLocaton(), vip);
        }
        param.remove("param");

        param.put("origin", m_strOrigin);
        param.put("sequenceValue", m_strSequenceValue);
        param.put("forecastDate", m_strForecastDate);
        param.put("forecastValidStart", m_strForecastValidStart);
        param.put("forecastValidEnd", m_strForecastValidEnd);
        param.put("forecastFileVersion", m_strForecastFileVersion);
        param.put("userName", m_strUserName);
        param.put("password", m_strPassword);
        param.put("coordinate", coordinate.toString());
        param.put("element", "TMP,2T");
        m_model.OutputLog(Model.LogLevel.Info, param.toJSONString());
        JSONObject dataTMP = executeMethod(m_strHost, param, HttpRequestUtils.CONTENT_TYPE_JSON);
        param.put("element", "ER12");
        m_model.OutputLog(Model.LogLevel.Info, param.toJSONString());
        JSONObject dataER12 = executeMethod(m_strHost, param, HttpRequestUtils.CONTENT_TYPE_JSON);
        JSONObject dataAltitude = executeMethod(m_strLocHost, param, HttpRequestUtils.CONTENT_TYPE_JSON);
        try {
            assistData(dataTMP, dataER12, dataAltitude, productDataMap);
        } catch (ParseException e) {
            m_model.OutputLog(Model.LogLevel.Error, e.getMessage());
            flag = false;
        }
        OnParamChanged();
        return flag;
    }

    private void calcRealDate() throws ParseException {
        String tmpDateStr = m_strDate;
        if("$DataStartTime".equals(m_strDate)){
            tmpDateStr = m_sdfYMD.format(m_model.m_dateDataStart);
        }
        Date tmpDate = m_sdfYMD.parse(tmpDateStr);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(tmpDate);
        calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + Integer.parseInt(m_strDayFormatType));
        m_strForecastDate = m_sdfYMD.format(calendar.getTime());
    }

    private JSONObject executeMethod(String wsdlUrl, JSONObject param, String contentType) {
        JSONObject data = null;
        try {
            data = HttpRequestUtils.httpPost(wsdlUrl, param, contentType);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data;
    }

    private void assistData(JSONObject dataTMP, JSONObject dataER12, JSONObject dataAltitude, Map<String, ProductData> productDataMap) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        JSONObject log = new JSONObject();
        m_listCSV.clear();
        String head = "userId,content,createTime,forecastDate";
        String type = "String,String,String,String";
        m_listCSV.add(head);
        m_listCSV.add(type);
        if (dataTMP.getInteger("status") != 1 || dataER12.getInteger("status") != 1) {
            return;
        }
        JSONObject tmpParam = dataTMP.getJSONObject("data");
        JSONObject er12Param = dataER12.getJSONObject("data");
        JSONObject altitudeParam = dataAltitude.getJSONObject("data");
        m_model.OutputLog(Model.LogLevel.Info, "TMP size:" + tmpParam.keySet().size());
        m_model.OutputLog(Model.LogLevel.Info, "ER12 size:" + er12Param.keySet().size());
        for (String coordinate : tmpParam.keySet()) {
            double altitude = altitudeParam.get(coordinate) != null ? altitudeParam.getDouble(coordinate) : 0;
            altitude = altitude <= -9000 ? 0 : altitude;
            JSONArray tmp = tmpParam.getJSONObject(coordinate).getJSONArray("TMP");
            JSONArray er12 = er12Param.getJSONObject(coordinate).getJSONArray("ER12");

            String content = calcSuitabeLevel(tmp, er12, altitude, coordinate, log);
            ProductData productData = productDataMap.get(coordinate);
            productData.setContent(content);
            m_listCSV.add(productData.toCSV(sdf.format(new Date()), m_strForecastDate));
        }
    }

    /**
     * 计算适宜等级
     *
     * @param tmp
     * @param er12
     * @param altitude
     * @param stationNum
     * @param log        @return
     */
    private String calcSuitabeLevel(JSONArray tmp, JSONArray er12, double altitude, String stationNum, JSONObject log) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("M月d日");
        String level = "";
        String rainStr = null;
        String noRainStr = null;
        int count = er12.size();

        if (count * 4 != tmp.size()) {
            System.out.println("count:count:");
            return null;
        }
        double avgTmp = calcAvgTmp(tmp);
        int rainDay = calcRainDay(er12);
        int[] allDay = calcContinuousNoRainDay(er12);

        int tmpMaxRainDay = 0;
        int tmpMaxNoRainDay = 0;
        int maxRainDay = 0;
        int maxNoRainDay = 0;
        int continuousNoRainDay = 0;
        int rainTime = 0;
        int noRainTime = 0;
        String rainMsg = "";
        Calendar calendar = Calendar.getInstance();

        for (int i = 0; i < allDay.length; i++) {
            int day = allDay[i];
            Date dateF = m_sdfYMD.parse(m_strForecastDate);

            calendar.setTime(dateF);
            calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + i + 1);
            dateF = calendar.getTime();
            rainMsg += sdf.format(dateF) + (day > 0 ? "有雨" : "无雨")
                    + (i < (Integer.parseInt(m_strCalcDay) - 1) ? "；\r\n" : "。\r\n");

            if (day > 0) {
                tmpMaxRainDay++;
                tmpMaxNoRainDay = 0;
            } else {
                tmpMaxNoRainDay++;
                tmpMaxRainDay = 0;
            }

            if ((maxRainDay - tmpMaxRainDay) < 0) {
                maxRainDay = tmpMaxRainDay;
                rainTime = i + 1;
            }
            if ((maxNoRainDay - tmpMaxNoRainDay) < 0) {
                maxNoRainDay = tmpMaxNoRainDay;
                noRainTime = i + 1;
            }
        }

        String logStr = ",continuousNoRainDay= " + continuousNoRainDay + "avgTmp=" + avgTmp + ",rainDay=" + rainDay;
        log.put(stationNum, logStr);

//        if (avgTmp < 10 || altitude > 650) {
        if (avgTmp < 10) {
            level = "不适宜";
//            if (altitude > 650) {
//                level = "尚未进入春播期";
//            }
        } else {
            if (maxNoRainDay >= 3 && rainDay < 4) {
                level = "适宜";
            } else if (maxNoRainDay >= 2 && rainDay <= 4) {
                level = "较适宜";
            } else {
                level = "不适宜";
            }
        }

        if (maxRainDay >= 3) {
            Date dateF = m_sdfYMD.parse(m_strForecastDate);
            calendar.setTime(dateF);
            calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + rainTime - maxRainDay + 1);
            dateF = calendar.getTime();

            Date dateL = m_sdfYMD.parse(m_strForecastDate);
            calendar.setTime(dateL);
            calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + rainTime);
            dateL = calendar.getTime();

            rainStr = sdf.format(dateF) + "～" + sdf.format(dateL) + "有降雨过程";
            if (!"不适宜".equalsIgnoreCase(level) && !"尚未进入春播期".equalsIgnoreCase(level)) {
                rainStr += "，对大田农事活动有影响";
            }
        }
        if (maxNoRainDay >= 3) {
            Date dateF = m_sdfYMD.parse(m_strForecastDate);
            calendar.setTime(dateF);
            calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + noRainTime - maxNoRainDay + 1);
            dateF = calendar.getTime();

            Date dateL = m_sdfYMD.parse(m_strForecastDate);
            calendar.setTime(dateL);
            calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + noRainTime);
            dateL = calendar.getTime();

            noRainStr = sdf.format(dateF) + "～" + sdf.format(dateL) + "持续无雨";
            if (!"不适宜".equalsIgnoreCase(level) && !"尚未进入春播期".equalsIgnoreCase(level)) {
                noRainStr += "，利于开展春耕春播";
            }
        }
        StringBuffer content = new StringBuffer();
        content.append("未来七天您的农田所在区域平均气温").append((int) Math.floor(avgTmp)).append("°C，春耕春播气象适宜度为：").append(level).append("。\r\n");
        if (rainTime < noRainTime) {
            if (rainStr != null) {
                content.append(rainStr);
                if (noRainStr != null) {
                    content.append("；").append(noRainStr).append("。\r\n");
                } else {
                    content.append("。\r\n");
                }
            } else {
                if (noRainStr != null) {
                    content.append(noRainStr).append("。\r\n");
                }
            }

        } else {
            if (noRainStr != null) {
                content.append(noRainStr);
                if (rainStr != null) {
                    content.append("；").append(rainStr).append("。\r\n");
                } else {
                    content.append("。\r\n");
                }
            } else {
                if (rainStr != null) {
                    content.append(rainStr).append("。\r\n");
                }
            }
        }
        content.append("每日晴雨如下：\r\n");
        content.append(rainMsg);
        return content.toString();
    }

    /**
     * 计算连续无雨天数
     *
     * @param er12
     * @return
     */
    private int[] calcContinuousNoRainDay(JSONArray er12) {
        int[] rainDay = new int[er12.size() / 2 - 1];
        for (int i = 0; i < er12.size() / 2 - 1; i++) {
            boolean sim = ((BigDecimal) er12.get(2 * i + 1)).doubleValue() > 0 && ((BigDecimal) er12.get(2 * i + 1)).doubleValue() < 9999;
            boolean dou = ((BigDecimal) er12.get(2 * i + 2)).doubleValue() > 0 && ((BigDecimal) er12.get(2 * i + 2)).doubleValue() < 9999;
            if (sim || dou) {
                rainDay[i] = 1;
            } else {
                rainDay[i] = 0;
            }
        }
        return rainDay;
    }

    /**
     * 计算下雨天数
     *
     * @param er12
     * @return
     */
    private int calcRainDay(JSONArray er12) {
        int day = 0;
        for (int i = 0; i < er12.size() / 2 - 1; i++) {
            boolean sim = ((BigDecimal) er12.get(2 * i + 1)).doubleValue() > 0 && ((BigDecimal) er12.get(2 * i + 1)).doubleValue() < 9999;
            boolean dou = ((BigDecimal) er12.get(2 * i + 2)).doubleValue() > 0 && ((BigDecimal) er12.get(2 * i + 2)).doubleValue() < 9999;
            if (sim || dou) {
                day++;
            }
        }
        return day;
    }

    /**
     * 计算平均温度
     *
     * @param tmp
     * @return
     */
    private double calcAvgTmp(JSONArray tmp) {
        int calcTmpDay = tmp.size() > 48 ? 48 : tmp.size();
        double totalAvg = 0;
        int calCount = 0;
        for (int i = 5; i < calcTmpDay - 4; i += 2) {
            totalAvg += ((BigDecimal) tmp.get(i)).doubleValue();
            calCount++;
        }
        return totalAvg / calCount;
    }

    public int GetOutputParam(Port port, ArrayList<Param> alParam) {
        int i = FindPort(port, false);
        if (i == -1) {
            System.out.println("Post Is Null");
            return 0;
        }

        alParam.add(new Param("ResultString", m_listCSV));
        return alParam.size();
    }

    List<String> m_listCSV = new ArrayList<String>();

    String m_strHost;
    String m_strVipHost;
    String m_strLocHost;
    String m_strUserName;
    String m_strPassword;
    String m_strOrigin;
    String m_strSequenceValue;
    String m_strForecastDate;
    String m_strDate;
    String m_strForecastValidStart;
    String m_strForecastValidEnd;
    String m_strForecastFileVersion;
    String m_strDayFormatType;
    String m_strCalcDay;

    SimpleDateFormat m_sdfYMD;
}
